// request.ts
import type { RequestOptions, ResponseData, CacheItem, AuthToken } from './types';

class Request {
  private baseUrl: string;
  private token: string | null = null;
  private refreshToken: string | null = null;
  private isRefreshing = false;
  private refreshQueue: ((token: string) => void)[] = [];
  private cache: Map<string, CacheItem> = new Map();
  private requestInterceptors: Array<(options: RequestOptions) => RequestOptions | Promise<RequestOptions>> = [];
  private responseInterceptors: Array<(response: Response) => Response | Promise<Response>> = [];

  constructor(baseUrl: string = '') {
    this.baseUrl = baseUrl;

    // 初始化时尝试从本地存储加载token
    this.loadToken();
  }

  // 设置基础URL
  public setBaseUrl(url: string): void {
    this.baseUrl = url;
  }

  // 设置token
  public setToken(token: string, refreshToken?: string): void {
    this.token = token;
    if (refreshToken) {
      this.refreshToken = refreshToken;
    }
    this.saveToken();
  }

  // 清除token
  public clearToken(): void {
    this.token = null;
    this.refreshToken = null;
    localStorage.removeItem('auth_token');
  }

  // 添加请求拦截器
  public addRequestInterceptor(
    interceptor: (options: RequestOptions) => RequestOptions | Promise<RequestOptions>
  ): void {
    this.requestInterceptors.push(interceptor);
  }

  // 添加响应拦截器
  public addResponseInterceptor(
    interceptor: (response: Response) => Response | Promise<Response>
  ): void {
    this.responseInterceptors.push(interceptor);
  }

  // 清除缓存
  public clearCache(): void {
    this.cache.clear();
  }

  // 从本地存储加载token
  private loadToken(): void {
    const tokenStr = localStorage.getItem('auth_token');
    if (tokenStr) {
      try {
        const tokenData: AuthToken = JSON.parse(tokenStr);
        this.token = tokenData.accessToken;
        this.refreshToken = tokenData.refreshToken;
      } catch (e) {
        console.error('Failed to parse token from localStorage', e);
      }
    }
  }

  // 保存token到本地存储
  private saveToken(): void {
    if (this.token && this.refreshToken) {
      const tokenData: AuthToken = {
        accessToken: this.token,
        refreshToken: this.refreshToken,
        expiresIn: 3600 // 默认1小时过期
      };
      localStorage.setItem('auth_token', JSON.stringify(tokenData));
    }
  }

  // 刷新token
  private async refreshAuthToken(): Promise<void> {
    if (!this.refreshToken) {
      throw new Error('No refresh token available');
    }

    this.isRefreshing = true;

    try {
      // 这里替换为实际的刷新token接口
      const response = await fetch(`${this.baseUrl}/auth/refresh`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          refreshToken: this.refreshToken,
        }),
      });

      if (!response.ok) {
        throw new Error('Failed to refresh token');
      }

      const data: AuthToken = await response.json();
      this.token = data.accessToken;
      this.refreshToken = data.refreshToken;
      this.saveToken();

      // 处理等待中的请求
      this.refreshQueue.forEach(cb => cb(data.accessToken));
      this.refreshQueue = [];
    } catch (error) {
      this.clearToken();
      throw error;
    } finally {
      this.isRefreshing = false;
    }
  }

  // 处理请求重试
  private async handleRetry<T>(
    url: string,
    options: RequestOptions,
    retryCount: number = 0
  ): Promise<T> {
    const { maxRetry = 3, retryDelay = 1000 } = options;

    try {
      return await this.request<T>(url, options, false);
    } catch (error) {
      if (retryCount >= maxRetry) {
        throw error;
      }

      await new Promise(resolve => setTimeout(resolve, retryDelay));
      return this.handleRetry<T>(url, options, retryCount + 1);
    }
  }

  // 处理缓存
  private async handleCache<T>(
    url: string,
    options: RequestOptions,
    fetchFn: () => Promise<T>
  ): Promise<T> {
    const { cacheKey, cacheTTL = 300000 } = options; // 默认缓存5分钟

    if (!cacheKey) {
      return fetchFn();
    }

    const now = Date.now();
    const cacheItem = this.cache.get(cacheKey);

    if (cacheItem && now - cacheItem.timestamp < cacheItem.ttl) {
      return cacheItem.data;
    }

    const data = await fetchFn();
    this.cache.set(cacheKey, {
      data,
      timestamp: now,
      ttl: cacheTTL,
    });

    return data;
  }

  // 核心请求方法
  public async request<T>(
    url: string,
    options: RequestOptions = {},
    checkAuth = true
  ): Promise<T> {
    // 处理请求拦截器
    let processedOptions = { ...options };
    for (const interceptor of this.requestInterceptors) {
      processedOptions = await interceptor(processedOptions);
    }

    // 处理查询参数
    let queryString = '';
    if (processedOptions.params) {
      queryString = new URLSearchParams(processedOptions.params).toString();
    }

    const fullUrl = `${this.baseUrl}${url}${queryString ? `?${queryString}` : ''}`;

    // 添加认证头
    const headers = new Headers(processedOptions.headers);
    if (this.token && !processedOptions.skipAuth && checkAuth) {
      headers.set('Authorization', `Bearer ${this.token}`);
    }

    // 处理缓存
    if (processedOptions.cacheKey) {
      return this.handleCache<T>(url, processedOptions, async () => {
        const response = await fetch(fullUrl, {
          ...processedOptions,
          headers,
        });

        // 处理响应拦截器
        let processedResponse = response;
        for (const interceptor of this.responseInterceptors) {
          processedResponse = await interceptor(processedResponse);
        }

        if (!processedResponse.ok) {
          throw new Error(`Request failed with status ${processedResponse.status}`);
        }

        return processedResponse.json();
      });
    }

    // 正常请求
    const response = await fetch(fullUrl, {
      ...processedOptions,
      headers,
    });

    // 处理响应拦截器
    let processedResponse = response;
    for (const interceptor of this.responseInterceptors) {
      processedResponse = await interceptor(processedResponse);
    }

    // 处理token过期
    if (processedResponse.status === 401 && this.refreshToken && !processedOptions.skipAuth && checkAuth) {
      if (this.isRefreshing) {
        // 如果正在刷新，将请求加入队列
        return new Promise<T>((resolve, reject) => {
          this.refreshQueue.push((newToken: string) => {
            headers.set('Authorization', `Bearer ${newToken}`);
            fetch(fullUrl, {
              ...processedOptions,
              headers,
            })
              .then(res => res.json())
              .then(resolve)
              .catch(reject);
          });
        });
      } else {
        // 刷新token并重试
        await this.refreshAuthToken();
        headers.set('Authorization', `Bearer ${this.token}`);
        return this.request<T>(url, {
          ...processedOptions,
          headers,
        });
      }
    }

    if (!processedResponse.ok) {
      throw new Error(`Request failed with status ${processedResponse.status}`);
    }

    return processedResponse.json();
  }

  // 快捷方法
  public async get<T>(url: string, options: RequestOptions = {}): Promise<T> {
    return this.request<T>(url, {
      ...options,
      method: 'GET',
    });
  }

  public async post<T>(url: string, body?: any, options: RequestOptions = {}): Promise<T> {
    return this.request<T>(url, {
      ...options,
      method: 'POST',
      body: JSON.stringify(body),
      headers: {
        'Content-Type': 'application/json',
        ...options.headers,
      },
    });
  }

  public async put<T>(url: string, body?: any, options: RequestOptions = {}): Promise<T> {
    return this.request<T>(url, {
      ...options,
      method: 'PUT',
      body: JSON.stringify(body),
      headers: {
        'Content-Type': 'application/json',
        ...options.headers,
      },
    });
  }

  public async delete<T>(url: string, options: RequestOptions = {}): Promise<T> {
    return this.request<T>(url, {
      ...options,
      method: 'DELETE',
    });
  }

  public async patch<T>(url: string, body?: any, options: RequestOptions = {}): Promise<T> {
    return this.request<T>(url, {
      ...options,
      method: 'PATCH',
      body: JSON.stringify(body),
      headers: {
        'Content-Type': 'application/json',
        ...options.headers,
      },
    });
  }
}

// 创建单例
const request = new Request(process.env.API_BASE_URL);

export default request;